package com.ecnu.common.utils;

import com.alibaba.fastjson2.JSON;
import com.ecnu.common.config.EmailConfig;
import com.ecnu.common.config.EmailConfigHolder;
import com.ecnu.common.constant.HttpStatus;
import com.ecnu.common.core.domain.HttpCode;
import com.ecnu.common.core.domain.model.AamsJwt;
import com.ecnu.common.core.domain.model.LoginUser;
import com.ecnu.common.core.page.TableDataInfo;
import com.ecnu.common.enums.XCNKIType;
import com.ecnu.common.exception.ServiceException;
import com.ecnu.common.utils.http.HttpUtils;
import com.ecnu.common.utils.ip.IpUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageInfo;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class OtherUtil {

    private static final Logger log = LoggerFactory.getLogger(OtherUtil.class);
    /**
     * 列表复制
     * @param aList
     * @param bClass
     * @return
     * @param <S>
     * @param <T>
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static <S, T> List<T> copy(List<S> aList, Class<T> bClass)
            throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        List<T> targetList = new ArrayList<>();
        for (S source : aList) {
            T target = bClass.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(source, target);
            targetList.add(target);
        }
        return targetList;
    }

    /**
     * 返回列表分页格式
     * @param list
     * @return
     */
    public static TableDataInfo tableSuccess(List<?> list) {
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(list);
        rspData.setTotal(new PageInfo(list).getTotal());
        rspData.setPageNum(new PageInfo(list).getPageNum());
        rspData.setPageSize(new PageInfo(list).getPageSize());
        return rspData;
    }

    /**
     * 统计用的测试转换（内容含有表头情况使用
     * @param list  列表
     * @param 原始的总数 原始的总数
     * @return
     */
    public static TableDataInfo tableSuccess2(List<?> list, long 原始的总数) {
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(list);
        rspData.setTotal(原始的总数);
        rspData.setPageNum(new PageInfo(list).getPageNum());
        rspData.setPageSize(new PageInfo(list).getPageSize());
        return rspData;
    }

    /**
     * 返回错误格式
     * @param msg
     * @return
     */
    public static TableDataInfo tableError(Object msg) {
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.ERROR);
        rspData.setMsg("操作失败，请联系管理员:\n" + msg.toString());
        return rspData;
    }

    /**
     * 分页(不过SQL的分页）
     * @param list
     * @param pageNum
     * @param pageSize
     * @param <T>
     * @return
     */
    public static <T> List<T> startPage(List<T> list, Integer pageNum,
                                        Integer pageSize) {
        if (list == null) {
            return list;
        }
        if (list.size() == 0) {
            return list;
        }
        Integer count = list.size(); // 记录总数
        Integer pageCount = 0; // 页数
        if (count % pageSize == 0) {
            pageCount = count / pageSize;
        } else {
            pageCount = count / pageSize + 1;
        }
        int fromIndex = 0; // 开始索引
        int toIndex = 0; // 结束索引
        if (pageNum != pageCount) {
            fromIndex = (pageNum - 1) * pageSize;
            toIndex = fromIndex + pageSize;
        } else {
            fromIndex = (pageNum - 1) * pageSize;
            toIndex = count;
        }
        List<T> pageList = list.subList(fromIndex, toIndex);
        return pageList;
    }
    /**
     * 获取当天最后一秒
     *
     * @param date
     * @return
     */
    public static Date getEndOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }

    /**
     * 内存分页工具(用于不多数据的情况下使用）
     *
     * @param source 列表
     * @param <T>
     * @return
     */
    public static <T> List<T> memoryPage(List<T> source, Integer 几条, Integer 几页) {
        int pageSize = 几条;
        int pageNum = 几页;
        int fromIndex = (pageNum - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, source.size());
        return source.subList(fromIndex, toIndex);
    }

    /**
     * 发送验证码
     *
     * @param toEmail
     * @param code
     * @return
     */
    public static Map<String, String> sendVerificationCode(String toEmail, String code) throws UnsupportedEncodingException {
        // 配置邮件服务器信息
        EmailConfig emailConfig = EmailConfigHolder.getConfig();//读取的事admin配置项中email的配置
        Properties properties = new Properties();
        properties.put("mail.smtp.host", emailConfig.getSmtp().getHost()); // 替换为你的SMTP服务器地址
        properties.put("mail.smtp.port", emailConfig.getSmtp().getPort());
        properties.put("mail.smtp.auth", "true");
        properties.put("mail.smtp.ssl.protocols", "TLSv1.2");
        properties.put("mail.smtp.ssl.enable", "true");

        // 创建会话
        Session session = Session.getInstance(properties, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(
                        emailConfig.getSmtp().getUsername(),
                        emailConfig.getSmtp().getPassword()); // 替换为你的邮箱和密码
            }
        });

        try {
            // 创建邮件消息
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(
                    emailConfig.getFromAddress(),
                    emailConfig.getFromName())); // 发件人邮箱
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail)); // 收件人邮箱
            message.setSubject("登录验证码"); // 邮件主题
            message.setText("尊敬的用户:你好! 您的验证码是：\n" + code + "\n 请妥善保管。(有效期为 5 分钟)；\n若非本人操作，请忽略本邮件，造成困扰向您致歉。"); // 邮件内容

            // 发送邮件
            Transport.send(message);
            HashMap<String, String> map = new HashMap<>();
            map.put("code", "200");
            map.put("msg", code);//验证码已发送到邮箱：
            return map; // 发送成功
        } catch (MessagingException e) {
            Logger logger = LoggerFactory.getLogger(OtherUtil.class);
            logger.error("验证码发送失败，具体原因为：\n"+e.getMessage());
            throw new RuntimeException("请核对邮箱是否正确，多次出现该问题请联系管理员老师");
        }
    }

    /**
     * 通用邮箱发送
     * @param toEmails 收件人们邮箱
     * @return
     */
    public static Boolean sendEmail(List<String> toEmails , String 主题, String 内容) {//获取收件人信息
        //去除空字符串
        List<String> filteredEmails = toEmails.stream()
                .filter(email -> StringUtils.isNotBlank(email))
                .collect(Collectors.toList());
        if (filteredEmails==null||filteredEmails.size()==0) {
            Logger logger = LoggerFactory.getLogger(OtherUtil.class);
            logger.error("邮件发送失败，具体原因为：\n 收件人邮箱为空");
            throw new ServiceException("邮件发送失败，具体原因为：\n 收件人邮箱为空，联系管理员调整",HttpStatus.ACCEPTED);
        }
        // 配置邮件服务器信息
        EmailConfig emailConfig = EmailConfigHolder.getConfig();//读取的事admin配置项中email的配置
        // 创建会话
        Session session = getSession(emailConfig);
        try {
            // 创建邮件消息
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(
                    emailConfig.getFromAddress(),
                    emailConfig.getFromName())); // 发件人邮箱
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(String.join(",", filteredEmails))); // 收件人邮箱
            message.setSubject(主题); // 邮件主题
            message.setText(内容); // 邮件内容

            // 发送邮件
            Transport.send(message);
            return true; // 发送成功
        } catch (MessagingException | UnsupportedEncodingException e) {
            Logger logger = LoggerFactory.getLogger(OtherUtil.class);
            logger.error("邮件发送失败，具体原因为：\n"+e.getMessage());
            throw new RuntimeException("请核对收件人邮箱是否正确，多次出现该问题请联系管理员老师");
        }
    }

    private static Session getSession(EmailConfig emailConfig) {
        Properties properties = new Properties();
        properties.put("mail.smtp.host", emailConfig.getSmtp().getHost()); // 替换为你的SMTP服务器地址
        properties.put("mail.smtp.port", emailConfig.getSmtp().getPort());
        properties.put("mail.smtp.auth", "true");
        properties.put("mail.smtp.ssl.protocols", "TLSv1.2");
        properties.put("mail.smtp.ssl.enable", "true");
        Session session = Session.getInstance(properties, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(
                        emailConfig.getSmtp().getUsername(),
                        emailConfig.getSmtp().getPassword()); // 替换为你的邮箱和密码
            }
        });
        return session;
    }


    /**
     * 生成指定长度的随机数字验证码
     *
     * @param length 验证码长度
     * @return 生成的验证码
     */
    public static String generateCode(int length) {
        StringBuilder code = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            code.append(random.nextInt(10)); // 生成0-9的数字
        }
        return code.toString();
    }

    public static String generateCodeLength(int length) {
        if (length < 4) {
            throw new IllegalArgumentException("密码长度至少为4位，以确保包含所有字符类型");
        }

        String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        String lower = "abcdefghijklmnopqrstuvwxyz";
        String digits = "0123456789";
        String special = SPECIAL_CHAR;

        String allCharacters = upper + lower + digits + special;

        Random random = new Random();
        StringBuilder sb = new StringBuilder();

        // 确保至少包含每种类型的字符各一个
        sb.append(upper.charAt(random.nextInt(upper.length())));
        sb.append(lower.charAt(random.nextInt(lower.length())));
        sb.append(digits.charAt(random.nextInt(digits.length())));
        sb.append(special.charAt(random.nextInt(special.length())));

        // 填充剩余长度
        for (int i = 4; i < length; i++) {
            int index = random.nextInt(allCharacters.length());
            sb.append(allCharacters.charAt(index));
        }

        // 打乱字符顺序
        List<Character> chars = sb.toString().chars()
                .mapToObj(c -> (char) c)
                .collect(Collectors.toList());
        Collections.shuffle(chars);

        return chars.stream()
                .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
                .toString();
    }





    /********/
    //定义特殊字符
    public static String SPECIAL_CHAR = "~!@#$%&*_.";


    public static boolean isValidPassword(String password) {
        return checkContainSpecialChar(password)
                && checkContainCase(password)
                && checkContainDigit(password);
    }

    /**
     * @brief   检测密码中是否包含数字
     * @param[in] password            密码字符串
     * @return  包含数字 返回true
     */
    public static boolean checkContainDigit(String password) {
        char[] chPass = password.toCharArray();
        for (int i = 0; i < chPass.length; i++) {
            if (Character.isDigit(chPass[i])) {
                return true;
            }
        }
        return false;
    }

    /**
     * @brief   检测密码中是否包含字母（不区分大小写）
     * @param[in] password            密码字符串
     * @return  包含字母 返回true
     */
    public static boolean checkContainCase(String password) {
        char[] chPass = password.toCharArray();
        for (int i = 0; i < chPass.length; i++) {
            if (Character.isLetter(chPass[i])) {
                return true;
            }
        }
        return false;
    }


    /**
     * @brief   检测密码中是否包含小写字母
     * @param[in] password            密码字符串
     * @return  包含小写字母 返回true
     */
    public static boolean checkContainLowerCase(String password) {
        char[] chPass = password.toCharArray();
        for (int i = 0; i < chPass.length; i++) {
            if (Character.isLowerCase(chPass[i])) {
                return true;
            }
        }
        return false;
    }


    /**
     * @brief   检测密码中是否包含大写字母
     * @param[in] password            密码字符串
     * @return  包含大写字母 返回true
     */
    public static boolean checkContainUpperCase(String password) {
        char[] chPass = password.toCharArray();
        for (int i = 0; i < chPass.length; i++) {
            if (Character.isUpperCase(chPass[i])) {
                return true;
            }
        }
        return false;
    }


    /**
     * @brief   检测密码中是否包含特殊符号
     * @param[in] password            密码字符串
     * @return  包含特殊符号 返回true
     */
    public static boolean checkContainSpecialChar(String password) {
        char[] chPass = password.toCharArray();
        for (int i = 0; i < chPass.length; i++) {
            if (SPECIAL_CHAR.indexOf(chPass[i]) != -1) {
                return true;
            }
        }
        return false;
    }

    /**
     * string ==> object(json方式的）
     *
     * @param mission
     * @return
     */
    private Object getList(String mission) {
        List<Map> checkLists = new ArrayList<>();
        if (StringUtils.isNotBlank(mission)) {
            try {
                mission = mission
                        .replaceAll("^\"+", "")  // 去除开头引号
                        .replaceAll("\"+$", "")
                        .replaceAll("^\"|\"$", "")
                        .replaceAll("\\\\\"", "\"")
                        .replaceAll("\\\\\\\\", "\\\\");
                checkLists = new ObjectMapper().readValue(mission, List.class);
            } catch (JsonProcessingException e) {
                return mission;
            }
        }
        return checkLists;
    }

    /**
     * 调整研学跳转接口
     * @param title
     * @param loginUser
     * @param proType
     * @return
     */
    public static String extracted(String title, LoginUser loginUser, String projectId, String proType) throws UnsupportedEncodingException {
        //解析HTML
        Document parse = Jsoup.parse(title);
        // 自定义输出格式，禁用换行符
        parse.outputSettings(new Document.OutputSettings().prettyPrint(false));
        //获取所有a标签
        Elements links = parse.select("a[href]");
        //需要查找的URL
        String targetUrl = "//x.cnki.net";

        for (Element link : links) {
            String href = link.attr("href");

            // 判断是否包含指定地址
            if (href.contains(targetUrl)) {
                //取token
                String url = "https://my.cnki.net/IntegrateLogin/api/IntegrateLoginApi/UserLogin";
                String ipAddr = IpUtils.getIpAddr();
                //包装参数
                HashMap<String, String> map = new HashMap<>();
                map.put(XCNKIType.Key.getCode(), XCNKIType.Key.getInfo());//学校秘钥
                map.put(XCNKIType.UserName.getCode(), XCNKIType.UserName.getInfo());//学校名称
//                map.put("UserIp", "58.38.54.113");//用户客户端ip
//                map.put("SubUserName", "a"+String.valueOf(loginUser.getUserId()));//登录用户id

                map.put("UserIp", ipAddr);//用户客户端ip
                map.put("SubUserName", String.valueOf(loginUser.getUserId()));//登录用户id
                String jsonString = JSON.toJSONString(map);
                String contentType = "application/json";
                //获取token
                String token = HttpUtils.sendPost(url, jsonString, contentType,new HashMap<>());
                if (StringUtils.isBlank(token)) {
                    continue;
                }
                HttpCode httpCode = JSON.parseObject(token, HttpCode.class);
                if (httpCode.getCode().equals("0")) {
                    log.error("知网获取token失败:"+httpCode.getMessage());
                    continue;
                }
                //获取aamsApi的jwt
                String jwt = getJwt(ipAddr);
                //读取用户信息
                String xcnkiUser = selectXCNKIUser(jwt, httpCode.getToken());
                //用户未绑定的情况跳转登录地址设为学习中心平台
                if (StringUtils.isBlank(xcnkiUser)) {
                    href="http://localhost:1234/home/detail?projectId="+projectId+"&typeId="+proType+"/";
                }else {
                    //有对接上的话添加团队
                    InstantTeam(xcnkiUser, jwt);
                }
                String geturl="https://my.cnki.net/IntegrateLogin/Redirect/Index?token="+httpCode.getToken()
//                        +"&ReturnUrl="+ URLEncoder.encode(href)+"&SubUserName="+loginUser.getUserId();
                        +"&SubUserName="+loginUser.getUserId()+"&ReturnUrl="+ URLEncoder.encode(href,"UTF-8");
                // 进行拼接替换
                link.attr("href", geturl);
//                System.out.println("Updated href: " + link.attr("href"));
            }
        }
        return parse.body().html();
//        project2.setTitle(parse.body().html());
    }

    public static void InstantTeam(String xcnkiUser, String jwt) {
        String url = "https://gateway.cnki.net/aamsapi/api/team/user?userId="+xcnkiUser+"&teamId=8a19916a-a173-45ac-8c5a-3b5f6a2d516d";
        String param="";
        String contentType = "application/json";
        HashMap<String, String> map = new HashMap<>();
        map.put("Authorization", "Bearer " + jwt);
        String team = HttpUtils.sendPost(url, param,contentType,map);
        System.out.println("team = " + team);
    }

    public static String selectXCNKIUser(String jwt, String token) {
        String url = "https://gateway.cnki.net/coreapi/api/user/accessToken/"+token;
        String Authorization= "Bearer "+jwt;
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", Authorization);
//        headers.put("Accept", "application/json");

        String response = HttpUtils.sendGet(url, headers);
//        String s = HttpUtils.sendGet(url);
        if (StringUtils.isBlank(response)) {
            return  "";
        }
        AamsJwt XCNKIUser  = JSON.parseObject(response, AamsJwt.class);
        if (!XCNKIUser.getSuccess()) {
            return "";
        }
        Map<String,String> map2 = JSON.parseObject(XCNKIUser.getContent(), Map.class);
        if (map2==null) {
            return "";
        }else {
            return map2.get("UserId");
        }

    }

    /**
     * 获取aamsApi的jwt
     * @return
     */
    public static String getJwt(String ipAddr) {
        // 获取当前时间戳
        long timestampInSeconds = Instant.now().getEpochSecond();
        String SignValue =
                "timestamp=" + timestampInSeconds+"&"+
                        XCNKIType.AppId.getCode() + "=" + XCNKIType.AppId.getInfo() + "&"+
                        XCNKIType.AppKey.getCode() + "=" + XCNKIType.AppKey.getInfo()  ;
        String Sign = sha1Hex(SignValue);
        HashMap<String, String> map = new HashMap<>();
        map.put("AppId", XCNKIType.AppId.getInfo());//appid
        map.put("Timestamp", String.valueOf(timestampInSeconds));//timestamp
        map.put("Sign", Sign);//sign
        map.put("ClientIp", ipAddr);
//        map.put("ClientIp", IpUtils.getIpAddr());
        String jsonString = JSON.toJSONString(map);
        String contentType = "application/json";
        //获取jwt
        String url = "https://gateway.cnki.net/coreapi/api/jwttoken/sign";
        String jwt = HttpUtils.sendPost(url, jsonString, contentType,new HashMap<>());
        if (StringUtils.isBlank(jwt)) {
            return  "";
        }
        AamsJwt aamsJwt  = JSON.parseObject(jwt, AamsJwt.class);

        if (!aamsJwt.getSuccess()) {
            log.error("知网获取jwt失败:"+aamsJwt.getMessage());
            return "";
        }
        Map<String,String> map2 = JSON.parseObject(aamsJwt.getContent(), Map.class);
        String JwtToken = map2.get("JwtToken");
        return JwtToken;
    }
    public static String sha1Hex(String input) {
        try {
            // 创建 SHA-1 消息摘要对象
            MessageDigest md = MessageDigest.getInstance("SHA-1");

            // 执行加密操作，得到字节数组
            byte[] digest = md.digest(input.getBytes());

            // 将字节数组转换为十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : digest) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0'); // 补零
                }
                hexString.append(hex);
            }

            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            log.error("SHA-1 加密失败：", e.getMessage());
            return null;
        }
    }

    public static String convertSpecialCharacters(String input) {
        if (StringUtils.isBlank(input)) {
            return input;
        }

        // 处理成对符号的计数器
        int quoteCount = 0;
        int singleQuoteCount = 0;

        StringBuilder result = new StringBuilder();

        for (char c : input.toCharArray()) {
            switch (c) {
                case '!':
                    result.append("！");
                    break;
                case '?':
                    result.append("？");
                    break;
                case ',':
                    result.append("，");
                    break;
                case '.':
                    result.append("。");
                    break;
                case ';':
                    result.append("；");
                    break;
                case ':':
                    result.append("：");
                    break;
                case '"':
                    // 处理成对引号
                    if (quoteCount % 2 == 0) {
                        result.append("“");
                    } else {
                        result.append("”");
                    }
                    quoteCount++;
                    break;
                case '\'':
                    // 处理成对单引号
                    if (singleQuoteCount % 2 == 0) {
                        result.append("‘");
                    } else {
                        result.append("’");
                    }
                    singleQuoteCount++;
                    break;
                case '(':
                    result.append("（");
                    break;
                case ')':
                    result.append("）");
                    break;
                case '[':
                    result.append("【");
                    break;
                case ']':
                    result.append("】");
                    break;
                case '{':
                    result.append("｛");
                    break;
                case '}':
                    result.append("｝");
                    break;
                case '-':
                    result.append("－");
                    break;
                case '_':
                    result.append("＿");
                    break;
                case '/':
                    result.append("／");
                    break;
                case '\\':
                    result.append("＼");
                    break;
                case '|':
                    result.append("｜");
                    break;
                case '@':
                    result.append("＠");
                    break;
                case '#':
                    result.append("＃");
                    break;
                case '$':
                    result.append("＄");
                    break;
                case '%':
                    result.append("％");
                    break;
                case '^':
                    result.append("＾");
                    break;
                case '&':
                    result.append("＆");
                    break;
                case '*':
                    result.append("＊");
                    break;
                case '+':
                    result.append("＋");
                    break;
                case '=':
                    result.append("＝");
                    break;
                case '<':
                    result.append("＜");
                    break;
                case '>':
                    result.append("＞");
                    break;
                case '~':
                    result.append("～");
                    break;
                case '`':
                    result.append("｀");
                    break;
                default:
                    result.append(c);
                    break;
            }
        }

        return result.toString();
    }
}
